﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Tomahawk.Runtime.Rendering.Materials
{
    #region SAS Parameter Builder
    public static class SASParameterBuilder
    {
        public static Dictionary<string, Type> table = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase)
        {
            {"STANDARDSGLOBAL", typeof(SASScriptParameter)},
            {"HEIGHT", typeof(SASViewportParameter)},
            {"FARCLIP", typeof(SASClipParameter)},
            {"NEARCLIP", typeof(SASClipParameter)},
            {"FOV", typeof(SASFovParameter)},
            {"ASPECTRATIO", typeof(SASAspectRatioParameter)},
            {"TIME", typeof(SASTimeParameter)},
            {"RANDOM", typeof(SASRandomParameter)},
            {"ELAPSEDTIME", typeof(SASTimeParameter)},
            {"POSITION", typeof(SASPositionParameter)},
            {"DIRECTION", typeof(SASDirectionParameter)},
            {"DIFFUSE", typeof(SASDiffuseParameter)},
            {"SPECULAR", typeof(SASSpecularParameter)},
            {"AMBIENT", typeof(SASAmbientParameter)},
            {"DIFFUSEMAP", typeof(SASTextureParameter)},
            {"NORMALMAP", typeof(SASTextureParameter)},
            {"SPECULARMAP", typeof(SASTextureParameter)},
            {"ENVIRONMENTMAP", typeof(SASTextureParameter)},
            {"LIGHTMAP", typeof(SASTextureParameter)},
            {"RENDERCOLORTARGET", typeof(SASRenderTargetParameter)},
            {"RENDERDEPTHSTENCILTARGET", typeof(SASDepthStencilParameter)},
            {"VIEWPORTPIXELSIZE", typeof(SASViewportPixelSizeParameter)},
            {"WORLD", typeof(SASTransformParameter)},
            {"VIEW", typeof(SASTransformParameter)},
            {"PROJECTION", typeof(SASTransformParameter)},
            {"WORLDVIEW", typeof(SASTransformParameter)},
            {"VIEWPROJECTION", typeof(SASTransformParameter)},
            {"WORLDVIEWPROJECTION", typeof(SASTransformParameter)},
            {"WORLDINVERSE", typeof(SASTransformParameter)},
            {"VIEWINVERSE", typeof(SASTransformParameter)},
            {"PROJECTIONINVERSE", typeof(SASTransformParameter)},
            {"WORLDVIEWINVERSE", typeof(SASTransformParameter)},
            {"VIEWPROJECTIONINVERSE", typeof(SASTransformParameter)},
            {"WORLDVIEWPROJECTIONINVERSE", typeof(SASTransformParameter)},
            {"WORLDTRANSPOSE", typeof(SASTransformParameter)},
            {"VIEWTRANSPOSE", typeof(SASTransformParameter)},
            {"PROJECTIONTRANSPOSE", typeof(SASTransformParameter)},
            {"WORLDVIEWTRANSPOSE", typeof(SASTransformParameter)},
            {"VIEWPROJECTIONTRANSPOSE", typeof(SASTransformParameter)},
            {"WORLDVIEWPROJECTIONTRANSPOSE", typeof(SASTransformParameter)},
            {"WORLDINVERSETRANSPOSE", typeof(SASTransformParameter)},
            {"VIEWINVERSETRANSPOSE", typeof(SASTransformParameter)},
            {"PROJECTIONINVERSETRANSPOSE", typeof(SASTransformParameter)},
            {"WORLDVIEWINVERSETRANSPOSE", typeof(SASTransformParameter)},
            {"VIEWPROJECTIONINVERSETRANSPOSE", typeof(SASTransformParameter)},
            {"WORLDVIEWPROJECTIONINVERSETRANSPOSE", typeof(SASTransformParameter)}
        };

        public static SASParameter Build(EffectParameter parameter)
        {
            Type type = null;
            SASParameter sasParameter = null;
            if ((parameter.Semantic != null) && (table.TryGetValue(parameter.Semantic, out type)))
            {
                sasParameter = Activator.CreateInstance(type) as SASParameter;
                sasParameter.Initialize(parameter);
            }
            else
            {
                sasParameter = new SASParameter();
                sasParameter.Initialize(parameter);
            }
            return sasParameter;
        }
    }
    #endregion

    #region SAS Parameter Exceptions
    public class SASWrongParameterTypeException : Exception
    {
        public SASWrongParameterTypeException() { }
        public SASWrongParameterTypeException(Exception inner) 
            : base("Wrong SAS parameter", inner)
        {
        }
    }
    public class SASUninitializedParameterException : Exception
    {
        public SASUninitializedParameterException() { }
        public SASUninitializedParameterException(Exception inner)
            : base("Uninitialized SAS parameter", inner)
        {
        }
    }
    #endregion

    #region SASTarget
    public sealed class SASTarget
    {
        public enum TargetType
        {
            Unknown,
            Light0,
            Light1,
            Light2,
            Camera
        }

        private TargetType type;
        public TargetType Type { get { return type; } }

        public SASTarget(EffectParameter parameter)
        {
            foreach (EffectAnnotation annotation in parameter.Annotations)
            {
                if (string.Compare(annotation.Name, "OBJECT", true) == 0)
                {
                    string value = annotation.GetValueString();

                    if ((string.Compare(value, "LIGHT0", true) == 0) ||
                        (string.Compare(value, "POINTLIGHT0", true) == 0) ||
                        (string.Compare(value, "SPOTLIGHT0", true) == 0))
                    {
                        type = TargetType.Light0; 
                    }
                    else if ((string.Compare(value, "LIGHT1", true) == 0) ||
                        (string.Compare(value, "POINTLIGHT1", true) == 0) ||
                        (string.Compare(value, "SPOTLIGHT1", true) == 0))
                    {
                        type = TargetType.Light1; 
                    }
                    else if ((string.Compare(value, "LIGHT2", true) == 0) ||
                        (string.Compare(value, "POINTLIGHT2", true) == 0) ||
                        (string.Compare(value, "SPOTLIGHT2", true) == 0))
                    {
                        type = TargetType.Light2; 
                    }
                    else if ((string.Compare(value, "CAMERA", true) == 0))
                    {
                        type = TargetType.Camera;
                    }
                    else
                    {
                        type = TargetType.Unknown;
                    }
                }
            }
        }
    }
    #endregion

    #region SAS Parameter
    public class SASParameter
    {
        [Flags]
        public enum UpdateType
        {
            NoUpdate,
            UpdatePerFrame,
            UpdatePerObject
        }

        protected EffectParameter parameter;
        public string Name
        {
            get
            {
                #region Safety Check
                #if DEBUG
                if (parameter == null) throw new SASUninitializedParameterException();
                #endif
                #endregion
                return parameter.Name;
            }
        }

        protected UpdateType updateMode = UpdateType.NoUpdate;
        public UpdateType UpdateMode { get { return updateMode; } }

        #region Parameter Value
        public enum SASParameterType
        {
            SASUndefined,
            SASBool,
            SASInt,
            SASFloat,
            SASString,
            SASVector2,
            SASVector3,
            SASVector4,
            SASMatrix,
            SASMatrixArray,
            SASTexture,
        };

        protected bool boolValue = false;
        protected int intValue = 0;
        protected float floatValue = 0.0f;
        protected string stringValue = "";
        protected Vector2 vector2Value = Vector2.Zero;
        protected Vector3 vector3Value = Vector3.Zero;
        protected Vector4 vector4Value = Vector4.Zero;
        protected Matrix matrixValue = Matrix.Identity;
        protected Matrix[] matrixArrayValue = null;
        protected Texture textureValue = null;

        protected SASParameterType sasType = SASParameterType.SASUndefined;
        public SASParameterType Type
        {
            get
            {
                #region Safety Check
                #if DEBUG
                if (parameter == null) throw new SASUninitializedParameterException();
                #endif
                #endregion
                if (sasType == SASParameterType.SASUndefined) sasType = GetSASType();
                return sasType;
            }
        }

        public void GetBoolValue(out bool value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            if (Type != SASParameterType.SASBool) throw new SASWrongParameterTypeException(); 
            #endif
            #endregion
            value = boolValue;
        }

        public void SetBoolValue(ref bool value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            if (value == boolValue) return;
            
            #region Begin Set
            #if DEBUG
            try { 
            #endif
            #endregion
            parameter.SetValue(value);
            #region End Set
            #if DEBUG
            } 
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
            boolValue = value;
        }

        public void GetFloatValue(out float value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            if (Type != SASParameterType.SASFloat) throw new SASWrongParameterTypeException();
            #endif
            #endregion
            value = floatValue;
        }

        public void SetFloatValue(ref float value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            if (value == floatValue) return;
            #region Begin Set
            #if DEBUG
            try
            {
            #endif
            #endregion
            parameter.SetValue(value);
            #region End Set
            #if DEBUG
            }
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
            floatValue = value;
        }

        public void GetIntValue(out int value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            if (Type != SASParameterType.SASInt) throw new SASWrongParameterTypeException();
            #endif
            #endregion
            value = intValue;
        }

        public void SetIntValue(ref int value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            if (value == intValue) return;
            #region Begin Set
            #if DEBUG
            try
            {
            #endif
            #endregion
            parameter.SetValue(value);
            #region End Set
            #if DEBUG
            }
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
            intValue = value;
        }

        public void GetMatrixValue(out Matrix value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            if (Type != SASParameterType.SASMatrix) throw new SASWrongParameterTypeException();
            #endif
            #endregion
            value = matrixValue;
        }

        public void SetMatrixValue(ref Matrix value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            if (value == matrixValue) return;
            #region Begin Set
            #if DEBUG
            try
            {
            #endif
            #endregion
            parameter.SetValue(value);
            #region End Set
            #if DEBUG
            }
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
            matrixValue = value;
        }

        public void GetMatrixArrayValue(out Matrix[] value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            if (Type != SASParameterType.SASMatrixArray) throw new SASWrongParameterTypeException();
            #endif
            #endregion
            value = matrixArrayValue;
        }

        public void SetMatrixArrayValue(ref Matrix[] value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            //[NOLVER]: This is uncompatible with XMAS for some reason, CLOPEZ told me xD
            //if (value.Equals(matrixArrayValue)) return;
            #region Begin Set
            #if DEBUG
            try
            {
            #endif
            #endregion
            parameter.SetValue(value);
            #region End Set
            #if DEBUG
            }
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
            matrixArrayValue = value;
        }

        public void GetStringValue(out string value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            if (Type != SASParameterType.SASString) throw new SASWrongParameterTypeException();
            #endif
            #endregion
            value = stringValue;
        }

        public void SetStringValue(ref string value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            if (value.Equals(stringValue)) return;
            #region Begin Set
            #if DEBUG
            try
            {
            #endif
            #endregion
            parameter.SetValue(value);
            #region End Set
            #if DEBUG
            }
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
            stringValue = value;
        }

        public void GetTextureValue(out Texture value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            if (Type != SASParameterType.SASTexture) throw new SASWrongParameterTypeException();
            #endif
            #endregion
            value = textureValue;
        }

        public void SetTextureValue(ref Texture value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            if (value.Equals(textureValue)) return;
            #region Begin Set
            #if DEBUG
            try
            {
            #endif
            #endregion
            parameter.SetValue(value);
            #region End Set
            #if DEBUG
            }
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
            textureValue = value;
        }

        public void GetVector2Value(out Vector2 value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            if (Type != SASParameterType.SASVector2) throw new SASWrongParameterTypeException();
            #endif
            #endregion
            value = vector2Value;
        }
        
        public void SetVector2Value(ref Vector2 value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            if (value == vector2Value) return;
            #region Begin Set
            #if DEBUG
            try
            {
            #endif
            #endregion
            parameter.SetValue(value);
            #region End Set
            #if DEBUG
            }
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
            vector2Value = value;
        }

        public void GetVector3Value(out Vector3 value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            if (Type != SASParameterType.SASVector3) throw new SASWrongParameterTypeException();
            #endif
            #endregion
            value = vector3Value;
        }
        
        public void SetVector3Value(ref Vector3 value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            if (value == vector3Value) return;
            #region Begin Set
            #if DEBUG
            try
            {
            #endif
            #endregion
            parameter.SetValue(value);
            #region End Set
            #if DEBUG
            }
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
            vector3Value = value;
        }

        public void GetVector4Value(out Vector4 value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            if (Type != SASParameterType.SASVector4) throw new SASWrongParameterTypeException();
            #endif
            #endregion
            value = vector4Value;
        }
        
        public void SetVector4Value(ref Vector4 value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            if (value == vector4Value) return;
            #region Begin Set
            #if DEBUG
            try
            {
            #endif
            #endregion
            parameter.SetValue(value);
            #region End Set
            #if DEBUG
            }
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
            vector4Value = value;
        }

        public void GetVectorValue(out Vector4 value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion

            switch (Type)
            {
                case SASParameterType.SASVector2: 
                    {
                        Vector4 newValue = Vector4.Zero;
                        newValue.X = vector2Value.X;
                        newValue.Y = vector2Value.Y;
                        value = newValue; 
                    } break;
                case SASParameterType.SASVector3: 
                    {
                        Vector4 newValue = Vector4.Zero;
                        newValue.X = vector3Value.X;
                        newValue.Y = vector3Value.Y;
                        newValue.Z = vector3Value.Z;
                        value = newValue;
                    } break;
                case SASParameterType.SASVector4: 
                    {
                        value = vector4Value; 
                    } break;
                default: throw new SASWrongParameterTypeException();
            }
        }

        public void SetVectorValue(ref Vector4 value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            if (value == vector4Value) return;
            #region Begin Set
            #if DEBUG
            try
            {
            #endif
            #endregion
            switch (Type)
            {
                case SASParameterType.SASVector2:
                    {
                        Vector2 newValue = Vector2.Zero;
                        newValue.X = value.X;
                        newValue.Y = value.Y;
                        parameter.SetValue(newValue);
                        vector2Value = newValue;
                    } break;
                case SASParameterType.SASVector3:
                    {
                        Vector3 newValue = Vector3.Zero;
                        newValue.X = value.X;
                        newValue.Y = value.Y;
                        newValue.Z = value.Z;
                        parameter.SetValue(newValue);
                        vector3Value = newValue;
                    } break;
                case SASParameterType.SASVector4:
                    {
                        parameter.SetValue(value);
                        vector4Value = value;
                    } break;
            }
            #region End Set
            #if DEBUG
            }
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
        }

        public void GetColorValue(out Color value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            if (Type != SASParameterType.SASVector4) throw new SASWrongParameterTypeException();
            #endif
            #endregion
            
            value = Color.White;
            value.R = (byte) (255 * vector4Value.X);
            value.G = (byte)(255 * vector4Value.Y);
            value.B = (byte)(255 * vector4Value.Z);
            value.A = (byte)(255 * vector4Value.W);
        }
        
        public void SetColorValue(ref Color value)
        {
            Vector4 newValue = value.ToVector4();

            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            if (newValue == vector4Value) return;
            #region Begin Set
            #if DEBUG
            try
            {
            #endif
            #endregion
            parameter.SetValue(newValue);
            #region End Set
            #if DEBUG
            }
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
            vector4Value = newValue;
        }

        public void GetQuaternionValue(out Quaternion value)
        {
            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            if (Type != SASParameterType.SASVector4) throw new SASWrongParameterTypeException();
            #endif
            #endregion
            
            value = Quaternion.Identity;
            value.X = vector4Value.X;
            value.Y = vector4Value.Y;
            value.Z = vector4Value.Z;
            value.W = vector4Value.W;
        }
        
        public void SetQuaternionValue(ref Quaternion value)
        {
            Vector4 newValue = Vector4.Zero;
            newValue.X = value.X;
            newValue.Y = value.Y;
            newValue.Z = value.Z;
            newValue.W = value.W;

            #region Safety Check
            #if DEBUG
            if (parameter == null) throw new SASUninitializedParameterException();
            #endif
            #endregion
            if (newValue == vector4Value) return;
            #region Begin Set
            #if DEBUG
            try
            {
            #endif
            #endregion
            parameter.SetValue(newValue);
            #region End Set
            #if DEBUG
            }
            catch (Exception inner) { throw new SASWrongParameterTypeException(inner); }
            #endif
            #endregion
            vector4Value = newValue;
        }
        #endregion

        private SASParameterType GetSASType()
        {
            if (parameter != null)
            {
                switch (parameter.ParameterType)
                {
                    case EffectParameterType.Bool:
                        {
                            return SASParameterType.SASBool;
                        }
                    case EffectParameterType.Int32:
                        {
                            return SASParameterType.SASInt;
                        }
                    case EffectParameterType.Single:
                        {
                            switch (parameter.ParameterClass)
                            {
                                case EffectParameterClass.Scalar: return SASParameterType.SASFloat;
                                case EffectParameterClass.Vector:
                                    switch (parameter.ColumnCount)
                                    {
                                        case 2: return SASParameterType.SASVector2;
                                        case 3: return SASParameterType.SASVector3;
                                        case 4: return SASParameterType.SASVector4;
                                        default: throw new NotImplementedException();
                                    }
                                case EffectParameterClass.MatrixColumns:
                                case EffectParameterClass.MatrixRows:
                                    {
                                        if (parameter.Elements.Count > 0) return SASParameterType.SASMatrixArray;
                                        return SASParameterType.SASMatrix;
                                    }
                                default: throw new NotImplementedException();
                            }
                        }
                    case EffectParameterType.String:
                        {
                            return SASParameterType.SASString;
                        }
                    case EffectParameterType.Texture:
                        {
                            return SASParameterType.SASTexture;
                        }
                }
            }

            return SASParameterType.SASUndefined;
        }

        public virtual bool Initialize(EffectParameter parameter)
        {
            this.parameter = parameter;

            switch (GetSASType())
            {
                case SASParameterType.SASBool: boolValue = parameter.GetValueBoolean(); break;
                case SASParameterType.SASInt: intValue = parameter.GetValueInt32(); break;
                case SASParameterType.SASFloat: floatValue = parameter.GetValueSingle(); break; 
                case SASParameterType.SASString: stringValue = parameter.GetValueString(); break;
                case SASParameterType.SASVector2: vector2Value = parameter.GetValueVector2(); break;
                case SASParameterType.SASVector3: vector3Value = parameter.GetValueVector3(); break;
                case SASParameterType.SASVector4: vector4Value = parameter.GetValueVector4(); break;
                case SASParameterType.SASMatrix: matrixValue = parameter.GetValueMatrix(); break;
                case SASParameterType.SASMatrixArray: matrixArrayValue = parameter.GetValueMatrixArray(parameter.Elements.Count); break;
                case SASParameterType.SASTexture: 
                    switch (parameter.ParameterType)
                    {
                        case EffectParameterType.Texture: textureValue = parameter.GetValueTexture2D(); break;
                        case EffectParameterType.Texture2D: textureValue = parameter.GetValueTexture2D(); break;
                        case EffectParameterType.Texture3D: textureValue = parameter.GetValueTexture3D(); break;
                        case EffectParameterType.TextureCube: textureValue = parameter.GetValueTextureCube(); break;
                        default: throw new SASWrongParameterTypeException();
                    }
                    break;
            }

            return true;
        }

        public virtual bool Update(SASRenderEnvironment environment)
        {
            return true;
        }
    }
    #endregion

    #region SASScriptParameter
    public class SASScriptParameter : SASParameter
    {
        public enum ScriptClassType
        {
            Object,
            Scene,
            ObjectOrScene
        }

        public enum ScriptOrderType
        {
            Standard,
            Preprocess,
            Postprocess
        }

        public enum ScriptOutputType
        {
            Color,
            Depth
        }

        #region Properties
        protected SASScript script;

        protected float scriptVersion;
        public float ScriptVersion { get { return scriptVersion; } }

        protected ScriptClassType scriptClass;
        public ScriptClassType ScriptClass { get { return scriptClass; } }

        protected ScriptOrderType scriptOrder;
        public ScriptOrderType ScriptOrder { get { return scriptOrder; } }

        protected ScriptOutputType scriptOutput;
        public ScriptOutputType ScriptOutput { get { return scriptOutput; } } 
        #endregion

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            GetFloatValue(out this.scriptVersion);
            foreach (EffectAnnotation annotation in parameter.Annotations)
            {
                string name = annotation.Name;
                string value = annotation.GetValueString();

                if (string.Compare(name, "SCRIPT", true) == 0)
                {
                    script = new SASScript(value);
                }
                else if (string.Compare(name, "SCRIPTCLASS", true) == 0)
                {
                    if (string.Compare(value, "OBJECT", true) == 0)
                    {
                        scriptClass = ScriptClassType.Object;
                    }
                    else if (string.Compare(value, "SCENE", true) == 0)
                    {
                        scriptClass = ScriptClassType.Scene;
                    }
                    else if (string.Compare(value, "OBJECTORSCENE", true) == 0)
                    {
                        scriptClass = ScriptClassType.ObjectOrScene;
                    }
                }
                else if (string.Compare(name, "SCRIPTORDER", true) == 0)
                {
                    if (string.Compare(value, "STANDARD", true) == 0)
                    {
                        scriptOrder = ScriptOrderType.Standard;
                    }
                }
                else if (string.Compare(name, "SCRIPTOUTPUT", true) == 0)
                {
                    if (string.Compare(value, "COLOR", true) == 0)
                    {
                        scriptOutput = ScriptOutputType.Color;
                    }
                    else if (string.Compare(value, "DEPTH", true) == 0)
                    {
                        scriptOutput = ScriptOutputType.Depth;
                    }
                }
            }
            return true;
        }

        public bool Execute(SASEffect sasEffect)
        {
            if (script != null)
            {
                SASScript.Context context = SASScript.Context.EmptyContext;
                context.sasEnvironment = Engine.Instance.RenderManager.Environment;
                context.sasEffect = sasEffect;

                return script.Execute(ref context);
            }

            return true;
        }
    }
    #endregion

    #region SASTransformParameter
    public class SASTransformParameter : SASParameter
    {
        protected enum Types
        {
            UNDEFINED,
            WORLD,
            VIEW,
            PROJECTION,
            WORLDVIEW,
            VIEWPROJECTION,
            WORLDVIEWPROJECTION,
            WORLDINVERSE,
            VIEWINVERSE,
            PROJECTIONINVERSE,
            WORLDVIEWINVERSE,
            VIEWPROJECTIONINVERSE,
            WORLDVIEWPROJECTIONINVERSE,
            WORLDTRANSPOSE,
            VIEWTRANSPOSE,
            PROJECTIONTRANSPOSE,
            WORLDVIEWTRANSPOSE,
            VIEWPROJECTIONTRANSPOSE,
            WORLDVIEWPROJECTIONTRANSPOSE,
            WORLDINVERSETRANSPOSE,
            VIEWINVERSETRANSPOSE,
            PROJECTIONINVERSETRANSPOSE,
            WORLDVIEWINVERSETRANSPOSE,
            VIEWPROJECTIONINVERSETRANSPOSE,
            WORLDVIEWPROJECTIONINVERSETRANSPOSE,
        }
        private static Dictionary<string, Types> TransformTable = new Dictionary<string, Types>(StringComparer.OrdinalIgnoreCase)
        {
            {"WORLD", Types.WORLD},
            {"VIEW", Types.VIEW},
            {"PROJECTION", Types.PROJECTION},
            {"WORLDVIEW", Types.WORLDVIEW},
            {"VIEWPROJECTION", Types.VIEWPROJECTION},
            {"WORLDVIEWPROJECTION", Types.WORLDVIEWPROJECTION},
            {"WORLDINVERSE", Types.WORLDINVERSE},
            {"VIEWINVERSE", Types.VIEWINVERSE},
            {"PROJECTIONINVERSE", Types.PROJECTIONINVERSE},
            {"WORLDVIEWINVERSE", Types.WORLDVIEWINVERSE},
            {"VIEWPROJECTIONINVERSE", Types.VIEWPROJECTIONINVERSE},
            {"WORLDVIEWPROJECTIONINVERSE", Types.WORLDVIEWPROJECTIONINVERSE},
            {"WORLDTRANSPOSE", Types.WORLDTRANSPOSE},
            {"VIEWTRANSPOSE", Types.VIEWTRANSPOSE},
            {"PROJECTIONTRANSPOSE", Types.PROJECTIONTRANSPOSE},
            {"WORLDVIEWTRANSPOSE", Types.WORLDVIEWTRANSPOSE},
            {"VIEWPROJECTIONTRANSPOSE", Types.VIEWPROJECTIONTRANSPOSE},
            {"WORLDVIEWPROJECTIONTRANSPOSE", Types.WORLDVIEWPROJECTIONTRANSPOSE},
            {"WORLDINVERSETRANSPOSE", Types.WORLDINVERSETRANSPOSE},
            {"VIEWINVERSETRANSPOSE", Types.VIEWINVERSETRANSPOSE},
            {"PROJECTIONINVERSETRANSPOSE", Types.PROJECTIONINVERSETRANSPOSE},
            {"WORLDVIEWINVERSETRANSPOSE", Types.WORLDVIEWINVERSETRANSPOSE},
            {"VIEWPROJECTIONINVERSETRANSPOSE", Types.VIEWPROJECTIONINVERSETRANSPOSE},
            {"WORLDVIEWPROJECTIONINVERSETRANSPOSE", Types.WORLDVIEWPROJECTIONINVERSETRANSPOSE}
        };

        protected Types type;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);

            this.type = Types.UNDEFINED;
            TransformTable.TryGetValue(parameter.Semantic, out this.type);

            switch (type)
            {
                case Types.VIEW:
                case Types.PROJECTION:
                case Types.VIEWPROJECTION:
                case Types.VIEWINVERSE:
                    {
                        this.updateMode = UpdateType.UpdatePerFrame;
                    } break;
                case Types.WORLD:
                case Types.WORLDVIEW:
                case Types.WORLDVIEWPROJECTION:
                case Types.WORLDVIEWINVERSE:
                case Types.WORLDINVERSETRANSPOSE:
                case Types.WORLDVIEWINVERSETRANSPOSE:
                    {
                        this.updateMode = UpdateType.UpdatePerObject;
                    } break;
            }
          
            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            switch (type)
            {
                case Types.WORLD:                   
                    {
                        SetMatrixValue(ref environment.world); 
                    } break;
                case Types.VIEW:                    
                    {
                        SetMatrixValue(ref environment.view); 
                    } break;
                case Types.PROJECTION:
                    {
                        SetMatrixValue(ref environment.projection);
                    } break;
                case Types.WORLDVIEW:               
                    {
                        if (environment.cache.worldView.dirty)
                        {
                            Matrix.Multiply(ref environment.world, ref environment.view, out environment.cache.worldView.matrix);
                            environment.cache.worldView.dirty = false;
                        }
                        SetMatrixValue(ref environment.cache.worldView.matrix);
                    } break;
                case Types.VIEWPROJECTION:          
                    {
                        if (environment.cache.viewProjection.dirty)
                        {
                            Matrix.Multiply(ref environment.view, ref environment.projection, out environment.cache.viewProjection.matrix);
                            environment.cache.viewProjection.dirty = false;
                        }
                        SetMatrixValue(ref environment.cache.viewProjection.matrix);
                    } break;
                case Types.WORLDVIEWPROJECTION:     
                    {
                        if (environment.cache.worldView.dirty)
                        {
                            Matrix.Multiply(ref environment.world, ref environment.view, out environment.cache.worldView.matrix);
                            environment.cache.worldView.dirty = false;
                        }
                        if (environment.cache.worldViewProjection.dirty)
                        {
                            Matrix.Multiply(ref environment.cache.worldView.matrix, ref environment.projection, out environment.cache.worldViewProjection.matrix);
                            environment.cache.worldViewProjection.dirty = false;
                        }
                        SetMatrixValue(ref environment.cache.worldViewProjection.matrix);
                    } break;
                case Types.VIEWINVERSE:
                    {
                        if (environment.cache.viewInverse.dirty)
                        {
                            Matrix.Invert(ref environment.view, out environment.cache.viewInverse.matrix);
                            environment.cache.viewInverse.dirty = false;
                        }
                        SetMatrixValue(ref environment.cache.viewInverse.matrix);
                    } break;
                case Types.WORLDVIEWINVERSE:
                    {
                        if (environment.cache.worldView.dirty)
                        {
                            Matrix.Multiply(ref environment.world, ref environment.view, out environment.cache.worldView.matrix);
                            environment.cache.worldView.dirty = false;
                        }
                        if (environment.cache.worldViewInverse.dirty)
                        {
                            Matrix.Invert(ref environment.cache.worldView.matrix, out environment.cache.worldViewInverse.matrix);
                            environment.cache.worldViewInverse.dirty = false;
                        }
                        SetMatrixValue(ref environment.cache.worldViewInverse.matrix);
                    } break;
                case Types.WORLDINVERSETRANSPOSE:   
                    {
                        if (environment.cache.worldInverse.dirty)
                        {
                            Matrix.Invert(ref environment.world, out environment.cache.worldInverse.matrix);
                            environment.cache.worldInverse.dirty = false;
                        }
                        if (environment.cache.worldInverseTranspose.dirty)
                        {
                            Matrix.Transpose(ref environment.cache.worldInverse.matrix, out environment.cache.worldInverseTranspose.matrix);
                            environment.cache.worldInverseTranspose.dirty = false;
                        }
                        SetMatrixValue(ref environment.cache.worldInverseTranspose.matrix);
                    } break;
                case Types.WORLDVIEWINVERSETRANSPOSE:
                    {
                        if (environment.cache.worldView.dirty)
                        {
                            Matrix.Multiply(ref environment.world, ref environment.view, out environment.cache.worldView.matrix);
                            environment.cache.worldView.dirty = false;
                        }
                        if (environment.cache.worldViewInverse.dirty)
                        {
                            Matrix.Invert(ref environment.cache.worldView.matrix, out environment.cache.worldViewInverse.matrix);
                            environment.cache.worldViewInverse.dirty = false;
                        }
                        if (environment.cache.worldViewInverseTranspose.dirty)
                        {
                            Matrix.Transpose(ref environment.cache.worldViewInverse.matrix, out environment.cache.worldViewInverseTranspose.matrix);
                            environment.cache.worldViewInverseTranspose.dirty = false;
                        }
                        SetMatrixValue(ref environment.cache.worldViewInverseTranspose.matrix);
                    } break;
                default: throw new NotImplementedException();
            }
            return true;
        }
    }
    #endregion

    #region SASViewportParameter
    public class SASViewportParameter : SASParameter
    {
        protected enum Types
        {
            UNDEFINED,
            HEIGHT,
        }

        private static Dictionary<string, Types> TransformTable = new Dictionary<string, Types>(StringComparer.OrdinalIgnoreCase)
        {
            {"HEIGHT", Types.HEIGHT},
        };

        protected Types type;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.updateMode = UpdateType.UpdatePerFrame;
            this.type = Types.UNDEFINED;
            TransformTable.TryGetValue(parameter.Semantic, out this.type);
            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            switch (type)
            {
                case Types.HEIGHT:
                    {
                        int height = Engine.Instance.GraphicsDevice.Viewport.Height;
                        SetIntValue(ref height);
                    } break;
                default: throw new NotImplementedException();
            }

            return true;
        }
    }
    #endregion

    #region SASClipParameter
    public class SASClipParameter : SASParameter
    {
        protected enum Types
        {
            UNDEFINED,
            FARCLIP,
            NEARCLIP
        }

        private static Dictionary<string, Types> TransformTable = new Dictionary<string, Types>(StringComparer.OrdinalIgnoreCase)
        {
            {"FARCLIP", Types.FARCLIP},
            {"NEARCLIP", Types.NEARCLIP},
        };

        protected Types type;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.updateMode = UpdateType.UpdatePerFrame;
            this.type = Types.UNDEFINED;
            TransformTable.TryGetValue(parameter.Semantic, out this.type);
            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            switch (type)
            {
                case Types.FARCLIP:
                    {
                        float zFar = Engine.Instance.CameraManager.ActiveCamera.ZFar;
                        SetFloatValue(ref zFar);
                    } break;
                case Types.NEARCLIP:
                    {
                        float zNear = Engine.Instance.CameraManager.ActiveCamera.ZNear;
                        SetFloatValue(ref zNear);
                    } break;
                default: throw new NotImplementedException();
            }

            return true;
        }
    }
    #endregion

    #region SASFovParameter
    public class SASFovParameter : SASParameter
    {
        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.updateMode = UpdateType.UpdatePerFrame;
            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            float fov = MathHelper.ToRadians(Engine.Instance.CameraManager.ActiveCamera.Fov);
            SetFloatValue(ref fov);
            return true;
        }
    }
    #endregion

    #region SASAspectRatioParameter
    public class SASAspectRatioParameter : SASParameter
    {
        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.updateMode = UpdateType.UpdatePerFrame;
            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            int w = Engine.Instance.GraphicDeviceManager.GraphicsDevice.Viewport.Width;
            int h = Engine.Instance.GraphicDeviceManager.GraphicsDevice.Viewport.Height;
            float aspect = (float)w / (float)h;
            SetFloatValue(ref aspect);
            return true;
        }
    }
    #endregion

    #region SASTimeParameter
    public class SASTimeParameter : SASParameter
    {
        protected enum Types
        {
            UNDEFINED,
            ELAPSEDTIME,
            TIME
        }

        private static Dictionary<string, Types> TransformTable = new Dictionary<string, Types>(StringComparer.OrdinalIgnoreCase)
        {
            {"ELAPSEDTIME", Types.ELAPSEDTIME},
            {"TIME", Types.TIME}
        };

        protected Types type;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.updateMode = UpdateType.UpdatePerFrame;
            this.type = Types.UNDEFINED;
            TransformTable.TryGetValue(parameter.Semantic, out this.type);
            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            switch (type)
            {
                case Types.ELAPSEDTIME:
                    {
                        SetFloatValue(ref environment.elapsedTime);
                    } break;
                case Types.TIME:
                    {
                        SetFloatValue(ref environment.time);
                    } break;
                default: throw new NotImplementedException();
            }

            return true;
        }
    }
    #endregion

    #region SASRandomParameter
    public class SASRandomParameter : SASParameter
    {
        protected Random random = new Random();

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.updateMode = UpdateType.UpdatePerObject;
            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            Vector4 randVector = Vector4.Zero;
            randVector.X = (float) random.NextDouble();
            randVector.Y = (float)random.NextDouble();
            randVector.Z = (float)random.NextDouble();
            randVector.W = (float)random.NextDouble();
            SetVector4Value(ref randVector);
            return true;
        }
    }
    #endregion
    
    #region SASPositionParameter
    public class SASPositionParameter : SASParameter
    {
        protected SASTarget target;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.updateMode = UpdateType.NoUpdate;
            this.target = new SASTarget(parameter);

            switch (this.target.Type)
            {
                case SASTarget.TargetType.Light0: 
                case SASTarget.TargetType.Light1:
                case SASTarget.TargetType.Light2: this.updateMode = UpdateType.UpdatePerFrame; break;
                case SASTarget.TargetType.Camera: this.updateMode = UpdateType.UpdatePerFrame; break;
            }

            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            switch (target.Type)
            {
                case SASTarget.TargetType.Light0: SetVectorValue(ref environment.light0.position); break;
                case SASTarget.TargetType.Light1: SetVectorValue(ref environment.light1.position); break;
                case SASTarget.TargetType.Light2: SetVectorValue(ref environment.light2.position); break;
                case SASTarget.TargetType.Camera: 
                    Vector3 translation = environment.view.Translation; 
                    SetVector3Value(ref translation); 
                    break;
            }
            return true;
        }
    }
    #endregion

    #region SASDirectionParameter
    public class SASDirectionParameter : SASParameter
    {
        protected SASTarget target;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.updateMode = UpdateType.NoUpdate;
            this.target = new SASTarget(parameter);

            switch (this.target.Type)
            {
                case SASTarget.TargetType.Light0:
                case SASTarget.TargetType.Light1:
                case SASTarget.TargetType.Light2: this.updateMode = UpdateType.UpdatePerFrame; break;
                case SASTarget.TargetType.Camera: this.updateMode = UpdateType.UpdatePerFrame; break;
            }

            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            switch (target.Type)
            {
                case SASTarget.TargetType.Light0: SetVectorValue(ref environment.light0.direction); break;
                case SASTarget.TargetType.Light1: SetVectorValue(ref environment.light1.direction); break;
                case SASTarget.TargetType.Light2: SetVectorValue(ref environment.light2.direction); break;
                case SASTarget.TargetType.Camera: 
                    Vector3 direction = environment.view.Forward;
                    SetVector3Value(ref direction); 
                    break;
            }
            return true;
        }
    }
    #endregion

    #region SASDiffuseParameter
    public class SASDiffuseParameter : SASParameter
    {
        protected SASTarget target;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.updateMode = UpdateType.UpdatePerFrame;
            this.target = new SASTarget(parameter);
            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            switch (target.Type)
            {
                case SASTarget.TargetType.Light0: SetVectorValue(ref environment.light0.diffuse); break;
                case SASTarget.TargetType.Light1: SetVectorValue(ref environment.light1.diffuse); break;
                case SASTarget.TargetType.Light2: SetVectorValue(ref environment.light2.diffuse); break;
            }
            return true;
        }
    }
    #endregion

    #region SASSpecularParameter
    public class SASSpecularParameter : SASParameter
    {
        protected SASTarget target;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.updateMode = UpdateType.UpdatePerFrame;
            this.target = new SASTarget(parameter);
            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            switch (target.Type)
            {
                case SASTarget.TargetType.Light0: SetVectorValue(ref environment.light0.specular); break;
                case SASTarget.TargetType.Light1: SetVectorValue(ref environment.light1.specular); break;
                case SASTarget.TargetType.Light2: SetVectorValue(ref environment.light2.specular); break;
            }
            return true;
        }
    }
    #endregion

    #region SASAmbientParameter
    public class SASAmbientParameter : SASParameter
    {
        protected SASTarget target;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.updateMode = UpdateType.UpdatePerFrame;
            this.target = new SASTarget(parameter);
            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            switch (target.Type)
            {
                case SASTarget.TargetType.Light0: SetVectorValue(ref environment.light0.ambient); break;
                case SASTarget.TargetType.Light1: SetVectorValue(ref environment.light1.ambient); break;
                case SASTarget.TargetType.Light2: SetVectorValue(ref environment.light2.ambient); break;
            }
            return true;
        }
    }
    #endregion

    #region SASDepthStencilParameter
    public class SASDepthStencilParameter : SASParameter
    {
        protected DepthStencilBuffer currentBuffer = null;
        internal DepthStencilBuffer CurrentBuffer { get { return currentBuffer; } }

        protected DepthStencilBuffer previousBuffer = null;
        internal DepthStencilBuffer PreviousBuffer { get { return previousBuffer; } set { previousBuffer = value; } }

        protected DepthFormat depthFormat = DepthFormat.Depth24Stencil8;
        protected Vector2 viewportRatio = new Vector2(1.0f, 1.0f);
        protected Vector2 dimensions = new Vector2(128.0f, 128.0f);

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);

            if (parameter.ParameterType != EffectParameterType.Texture)
            {
                throw new Exception(string.Format("{0} semantic is only valid with texture parameters", parameter.Semantic));
            }

            foreach (EffectAnnotation annotation in parameter.Annotations)
            {
                if (string.Compare(annotation.Name, "VIEWPORTRATIO", true) == 0)
                {
                    viewportRatio = annotation.GetValueVector2();
                }
                else if (string.Compare(annotation.Name, "DIMENSIONS", true) == 0)
                {
                    dimensions = annotation.GetValueVector2();
                }
                else if (string.Compare(annotation.Name, "FORMAT", true) == 0)
                {
                    if (string.Compare(annotation.GetValueString(), "D24S8", true) == 0)
                    {
                        depthFormat = DepthFormat.Depth24Stencil8;
                    }
                }
            }

            return true;
        }

        internal bool LoadDepthStencilBuffer(GraphicsDevice gd)
        {
            UnloadDepthStencilBuffer();

            previousBuffer = null;

            lock (Engine.ResourceLock)
            {
                currentBuffer = new DepthStencilBuffer(
                        gd,
                        (int)(viewportRatio != null ? (gd.Viewport.Width * viewportRatio.X) : dimensions.X),
                        (int)(viewportRatio != null ? (gd.Viewport.Height * viewportRatio.Y) : dimensions.Y),
                        depthFormat,
                        gd.PresentationParameters.MultiSampleType,
                        gd.PresentationParameters.MultiSampleQuality
                    );
            }

            return (currentBuffer != null);
        }

        internal bool UnloadDepthStencilBuffer()
        {
            if (currentBuffer != null)
            {
                currentBuffer.Dispose();
                return true;
            }

            previousBuffer = null;

            return false;
        }
    }
    #endregion

    #region SASRenderTargetParameter
    public class SASRenderTargetParameter : SASParameter
    {
        protected RenderTarget2D renderTarget = null;
        internal RenderTarget2D RenderTarget { get { return renderTarget; } }

        protected SurfaceFormat surfaceFormat = SurfaceFormat.Color;
        protected Vector2 viewportRatio = new Vector2(1.0f, 1.0f);
        protected Vector2 dimensions = new Vector2(128.0f, 128.0f);
        protected int mipLevels = 1;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);

            if (parameter.ParameterType != EffectParameterType.Texture) 
            {
                throw new Exception(string.Format("{0} semantic is only valid with texture parameters", parameter.Semantic));
            }

            foreach (EffectAnnotation annotation in parameter.Annotations)
            {
                if (string.Compare(annotation.Name, "VIEWPORTRATIO", true) == 0)
                {
                    viewportRatio = annotation.GetValueVector2();
                }
                else if (string.Compare(annotation.Name, "DIMENSIONS", true) == 0)
                {
                    dimensions = annotation.GetValueVector2();
                }
                else if (string.Compare(annotation.Name, "FORMAT", true) == 0)
                {
                    if (string.Compare(annotation.GetValueString(), "R8G8B8", true) == 0)
                    {
                        surfaceFormat = SurfaceFormat.Color;
                    }
                    else if (string.Compare(annotation.GetValueString(), "A8R8G8B8", true) == 0)
                    {
                        surfaceFormat = SurfaceFormat.Color;
                    }
                    else if (string.Compare(annotation.GetValueString(), "X8R8G8B8", true) == 0)
                    {
                        surfaceFormat = SurfaceFormat.Color;
                    }
                }
            }

            return true;
        }

        internal bool LoadRenderTarget(GraphicsDevice gd)
        {
            UnloadRenderTarget();

            lock (Engine.ResourceLock)
            {
                renderTarget = new RenderTarget2D(
                        gd,
                        (int)(viewportRatio != null ? (gd.Viewport.Width * viewportRatio.X) : dimensions.X),
                        (int)(viewportRatio != null ? (gd.Viewport.Height * viewportRatio.Y) : dimensions.Y),
                        mipLevels,
                        surfaceFormat,
                        gd.PresentationParameters.MultiSampleType,
                        gd.PresentationParameters.MultiSampleQuality
                    );
            }

            return (renderTarget != null);
        }

        internal bool UnloadRenderTarget()
        {
            if (renderTarget != null)
            {
                renderTarget.Dispose();
                return true;
            }

            return false;
        }
    }
    #endregion

    #region SASViewportPixelSizeParameter
    public class SASViewportPixelSizeParameter : SASParameter
    {
        public override bool Initialize(EffectParameter parameter)
        {
            bool result = base.Initialize(parameter);

            Vector2 pixelSize = Vector2.Zero;
            pixelSize.X = Engine.Instance.GraphicsDevice.Viewport.Width;
            pixelSize.Y = Engine.Instance.GraphicsDevice.Viewport.Height;
            SetVector2Value(ref pixelSize);

            return result;
        }
    }
    #endregion

    #region SASTextureDiffuseParameter
    public class SASTextureParameter : SASParameter
    {
        protected enum TextureUsage
        {
            Undefined,
            Diffuse,
            Normal,
            Specular,
            Environment,
            Illumination
        }
        protected TextureUsage usage;

        public override bool Initialize(EffectParameter parameter)
        {
            base.Initialize(parameter);
            this.updateMode = UpdateType.UpdatePerObject;

            if (string.Compare(parameter.Semantic, "DIFFUSEMAP", true) == 0)
            {
                usage = TextureUsage.Diffuse;
            }
            else if (string.Compare(parameter.Semantic, "NORMALMAP", true) == 0)
            {
                usage = TextureUsage.Normal;
            }
            else if (string.Compare(parameter.Semantic, "SPECULARMAP", true) == 0)
            {
                usage = TextureUsage.Specular;
            }
            else if (string.Compare(parameter.Semantic, "ENVIRONMENTMAP", true) == 0)
            {
                usage = TextureUsage.Environment;
            }
            else if (string.Compare(parameter.Semantic, "LIGHTMAP", true) == 0)
            {
                usage = TextureUsage.Illumination;
            }

            return true;
        }

        public override bool Update(SASRenderEnvironment environment)
        {
            switch (usage)
            {
                case TextureUsage.Diffuse: if (environment.DiffuseMap != null) SetTextureValue(ref environment.DiffuseMap); break;
                case TextureUsage.Normal: if (environment.NormalMap != null) SetTextureValue(ref environment.NormalMap); break;
                case TextureUsage.Specular: if (environment.SpecularMap != null) SetTextureValue(ref environment.SpecularMap); break;
                case TextureUsage.Environment: if (environment.EnvironmentMap != null) SetTextureValue(ref environment.EnvironmentMap); break;
                case TextureUsage.Illumination: if (environment.LightMap != null) SetTextureValue(ref environment.LightMap); break;
            }

            return true;
        }
    }
    #endregion
}
